import { cloneDeep, pick } from 'lodash';
import { errorHandler, requestAbort, requestAbortByPrefix } from '@/utils';
import { CANCEL_HTTP_STATUS } from '@/constants';

const INITIAL_LIST_VALUE = {
  pageNum: 1,
  pageSize: 10,
  data: [],
  loading: false,
  total: 0,
};

class ListStore {
  list = {};

  // 缓存的初始list
  cacheInitialList = {};

  /**
   * 列表配置，通过config实现多列表支持
   * @param config[]
   * @param config.listName 列表名
   * @param config.pageNum 列表初始pageNum
   * @param config.pageSize 列表初始pageSize
   */
  constructor(configArr) {
    configArr.forEach(({ listName, ...restConfig }) => {
      this.list = {
        ...this.list,
        [listName]: { ...INITIAL_LIST_VALUE, ...pick(restConfig, ['pageNum', 'pageSize']) },
      };
    });
    // 缓存初始list - 用于后续重置
    this.cacheInitialList = cloneDeep(this.list);
  }

  // 重置
  resetList = listName => {
    if (!this.list[listName]) {
      throw new Error(`${listName} not found`);
    }
    this.list[listName] = { ...(this.cacheInitialList[listName] || INITIAL_LIST_VALUE) };
  };

  setList = (listName, params = {}) => {
    this.list = {
      ...this.list[listName],
      ...params,
    };
  };

  /**
   * 加载列表数据
   * @param params
   * @param params.requestTaskNamePrefix http请求任务名前缀
   * @param params.requestTaskName http请求任务名
   * @param params.listName 列表名
   * @param params.loadAction 动作，可选值为 reset/pageSizeChange/pageNumChange
   * @param params.loadDataFunc 请求函数
   * @param params.pageSize pageSize - 一般用于 变更每页显示条数 时传入
   * @param params.pageNum pageNum - 一般用于 变更当前页 时传入
   * @param params.skipErrorHandler 是否跳过错误处理 - 若跳过，抛出错误；否则调用 errorHandler 处理错误
   */
  loadList = async ({
    requestTaskName,
    requestTaskNamePrefix,
    listName,
    loadAction,
    loadDataFunc,
    pageSize: inputPageSize,
    pageNum: inputPageNum,
    skipErrorHandler = false,
  }) => {
    if (!this.list[listName]) {
      throw new Error(`${listName} not found`);
    }

    /**
     * 若传入requestTaskNamePrefix或requestName，此时直接中止进行中的请求；否则，进行loading校验
     */
    if (requestTaskNamePrefix) {
      requestAbortByPrefix(requestTaskNamePrefix);
    } else if (requestTaskName) {
      requestAbort(requestTaskName);
    } else {
      if (this.list[listName].loading) {
        return;
      }
    }

    // 缓存当前节点的pageNum/pageSize - 用于加载失败时恢复
    const { pageNum: pointPageNum, pageSize: pointPageSize } = this.list[listName];
    const selfCachePagination = {
      pageNum: pointPageNum,
      pageSize: pointPageSize,
    };

    switch (loadAction) {
      case 'pageSizeChange': {
        this.list[listName].pageNum = 1;
        this.list[listName].pageSize = inputPageSize;
        break;
      }
      case 'pageNumChange':
        this.list[listName].pageNum = inputPageNum;
        break;
      default: {
        this.resetList(listName);
      }
    }

    const { pageNum, pageSize } = this.list[listName];
    try {
      this.list[listName].loading = true;
      const result = await loadDataFunc({
        pageNum,
        pageSize,
      });
      const { total = 0, data = [] } = result || {};
      this.list[listName] = {
        ...this.list[listName],
        total,
        data,
        loading: false,
      };
    } catch (error) {
      if (!(error?.status === CANCEL_HTTP_STATUS)) {
        this.list[listName] = {
          ...this.list[listName],
          ...selfCachePagination,
          loading: false,
        };
      }

      if (skipErrorHandler) {
        throw error;
      }
      errorHandler({ error });
    }
  };

  // 更新列表某项值
  updateListDataItem = (listName, { matchedKey, matchedValue, modifiedParams }) => {
    if (!this.list[listName]) {
      throw new Error(`${listName} not found`);
    }
    this.list[listName].data = this.list[listName].data.map(item => {
      if (item[matchedKey] === matchedValue) {
        return {
          ...item,
          ...modifiedParams,
        };
      }
      return item;
    });
  };
}

export default ListStore;
